/*
 * 自述题
 * 1、我理解的异步编程是为了解决单线程模式中对于耗费时间的任务的特殊处理，防止系统因大量耗时出现的假死现象。
 * 2、已经完成的耗时api任务会进入消息队列等待被执行，eventloop是将队列中的任务重新压入调用栈
 * 3、宏任务是指耗时的异步webapi，如setTimeout,setInterval等
 * 4、微任务是指程序中promise，process.nextTick等产生的异步任务
 */
/* 代码题 */
// 一
const p1 = new Promise(resolve=>{resolve("hello")});
const p2 = new Promise(resolve=>{resolve("lagou")});
const p3 = new Promise(resolve=>{resolve("I♥U")});
Promise.all([p1,p2,p3]).then(res=>{console.log(res.join(" "))})

// 二
const fp=require('lodash/fp')
//数据
//horsepower马力,dollar_value价格,in stock库存
const cars=[
  {name:'Ferrari FF',horsepower:660,dollar_value:700000,in_stock:true},
  {name:'Spykerc12zaga to',horsepower : 650,dollar_value:648000,in_stock:false} ,
  {name:'Jaguar XKR-S',horsepower:550,dollar_value:132000,in_stock:false},
  {name:'Audi R 8',horsepower : 525,dollar_value:114200,in_stock:false} ,
  {name:'Aston Martin One-77',horsepower : 750,dollar_value:1850000,in_stock:true},
  {name:'Pagani Huay ra',horsepower:700,dollar_value:1300000,in_stock:false},
]

// 1
let isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last);
console.log(isLastInStock(cars));

// 2
let isFirstName = fp.flowRight(fp.prop('name'), fp.first);
console.log(isFirstName(cars));

// 3
let _average=function (xs){
 return fp.reduce(fp.add, 0, xs) / xs.length
}//<-无须改动
// let averageDollarValue=function(cars){
//   let dollar_values=fp.map(function(car) {
//     return car.dollar_value
//   }, cars)
//   return _average(dollar_values)
// }

const _ = require("lodash");
let averageDollarValue = _.flowRight(_average, fp.map(car=>car.dollar_value))
console.log(averageDollarValue(cars));

// 4
let _underscore = fp.replace(/\W+/g,'_');
// const log=v=>{console.log(v);return v;}
let sanitizeNames = fp.flowRight(fp.map(_underscore), fp.map(fp.toLower));
console.log(sanitizeNames(["Hello Word","msdf dfa"]));

// 三
// support.j s
class Container {
  static of(value) {
    return new Container(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return Container.of(fn(this._value))
  }
}
class Maybe {
  static of(x) {
    return new Maybe(x)
  }
  isNothing() {
    return this._value === null ||
      this._value === undefined
  }
  constructor(x) {
    this._value = x
  }
  map(fn) {
    return this.isNothing() ? this : Maybe.of(fn(this._value))
  }
}
// module.exports = { Maybe, Container }

// 1
// app.js
// const fp = require('lodash/fp')
// const { Maybe, Container } = require('./support')
let maybe = Maybe.of([5, 6, 1])
// console.log(maybe);
let exl = () => {
  //你需要实现的函数...
  return maybe.map(x=>fp.map(fp.add(3),x))
}
console.log(exl())

// 2
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
let ex2 = () => {
  //你需要实现的函数...
  return xs.map(x=>fp.first(x));
}
console.log(ex2())

// 3
let safeProp = fp.curry(function (x, o) {
  return Maybe.of(o[x])
})
let user = { id: 2, name: 'Albert' }
let ex3 = () => {
  //你需要实现的函数...
  return safeProp("name",user).map(x=>fp.first(x))
}
console.log(ex3())

// 4
let ex4 = function (n) {
  // if (n) {
  //   return parseInt(n)
  // }
  return Maybe.of(n).map(parseInt)
}
console.log(ex4(1),1)
console.log(ex4(null),2)
console.log(ex4(),3)

// 四
const PENDING ="pending"; //等待状态
const FULFILLED = "fulfilled"; // 成功状态
const REJECTED = "rejected"; //失败状态

class MyPromise{
  constructor (executor) {
    try{;
      executor(this.resolve,this.reject);
    }catch(e){
      this.reject(e)
    }
  }
  // promist状态
  status=PENDING;
  // success
  value=undefined;
  // fulfill
  reason=undefined;
  // 成功回调
  successCallback=[];
  // 失败回调
  failCallback=[];
  resolve=value=>{
    // 判断状态不为等待，阻止执行
    if(this.status !== PENDING) return;
    // 更改状态为成功
    this.status=FULFILLED;
    // 保存成功的值
    this.value=value;
    // 判断成功回调是否存在，存在=>调用
    // this.successCallback && this.successCallback(this.value);
    while(this.successCallback.length) this.successCallback.shift()();
  }
  reject=reason=>{
    // 判断状态不为等待，阻止执行
    if(this.status !== PENDING) return;
    // 更改状态为失败
    this.status=REJECTED;
    // 保存失败的原因
    this.reason=reason;
    // 判断失败回调是否存在，存在=>调用
    // this.failCallback && this.failCallback(this.reason);
    while(this.failCallback.length) this.failCallback.shift()();

  }
  then(successCallback,failCallback){
    successCallback=successCallback?successCallback:value=>value;
    failCallback=failCallback?failCallback:reason=> {throw (reason);}
    let promise2 = new Promise((resolve,reject)=>{
      //判断状态
      if(this.status === FULFILLED){
        setTimeout(() => {
          try{
            let x=successCallback(this.value);
            // 判断x的值是普通值还是promise对象
            // 如果是普通值，直接调用resolve
            // 如果是promise对象，查看promise对象返回的结果
            // 再根据promise对象返回结果，决定调用resolve还是reject
            resolvePromise(promise2,x,resolve,reject);
          }catch(e){
            reject(e);
          }
        }, 0);
      }else if(this.status === REJECTED){
        setTimeout(() => {
          try{
            let x=failCallback(this.reason);
            resolvePromise(promise2,x,resolve,reject);
          }catch(e){
            reject(e);
          }
        }, 0);
      }else{
        //等待
        // 将成功回调和失败回调存储起来
        this.successCallback.push(()=>{
          setTimeout(() => {
            try{
              let x=successCallback(this.value);
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              reject(e);
            }
          }, 0);
        });
        this.failCallback.push(()=>{
          setTimeout(() => {
            try{
              let x=failCallback(this.reason);
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              reject(e);
            }
          }, 0);
        });
      }
    });
    return promise2
  }
  finally(callback){
    return this.then(value=>{
      return MyPromise.resolve(callback()).then(()=>value);
    }, reason=>{
      return MyPromise.resolve(callback()).then(()=>{throw reason});
    })
  }
  catch(failCallack){
    return this.then(undefined,failCallack)
  }
  static all(array){
    let result=[];
    let index=0;
    return new MyPromise((resolve,reject)=>{
      function addData(key,value){
        result[key]=value;
        index++;
        if(index===array.length){
          resolve(result);
        }
      }
      for(let i=0;i<array.length;i++){
        let current = array[i];
        if(current instanceof MyPromise){
          // promise 对象
          current.then(value=>addData(i,value),reason=>reject(reason))
        }else{
          // 普通值
          addData(i,array[i]);
        }
      }
    })
  }
  static resolve(value){
    if(value instanceof MyPromise) return value;
    return new MyPromise(resolve=>resolve(value))
  }
}
function resolvePromise(promise2,x,resolve,reject){
  if(promise2===x){
    return reject(new TypeError('Chaining cucle detected for promise #<Promise>'))
  }
  if(x instanceof MyPromise){
    // promise 对象
    // x.then(value=>resolve(value),reason=>reject(reason))
    x.then(resolve,reject)
  }else{
    // 普通值
    resolve(x);
  }
}